package simpleConfig_v1

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
)

var sys string
var flag int

//three layer, like [server] -> protocol -> http
type Config [](map[string](map[string]string))

func init() {
	flag = 0
	if runtime.GOOS == "windows" {
		sys = ";"
	} else {
		sys = "#"
	}
}

type Listener interface {
	Listen(filename string)
}

type ListenFunc func(filename string) (Config, error)

func (fun ListenFunc) Listen(filename string) (Config, error) {
	return fun(filename)
}

//Watch = load + read + listen
func Watch(filename string, listener ListenFunc) (Config, error) {
	//load + read
	if flag == 0 {
		config := new(Config)
		configuration, err := config.ReadConfig(filename)
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println("")
			fmt.Println(filename + "文件原始的的配置信息如下：")
			//fmt.Println(configuration)
			for key, value := range configuration {
				fmt.Println(key, ":", value)
			}
			fmt.Println("")
		}
		flag = 1
	}

	//listen
	return listener.Listen(filename)
}

/*================================= main()=== =====================*/
/*
func main() {
	var listener ListenFunc = OnConfigChange
	filename := "config.ini"

	for {
		configuration, err := Watch(filename, listener)
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println(filename + "文件发生改变，改变后的配置信息如下：")
			//fmt.Println(configuration)
			for key, value := range configuration {
				fmt.Println(key, ":", value)
			}
			fmt.Println("")
		}

		time.Sleep(time.Duration(2) * time.Second)
	}

}
*/
/*================================= main()=== =====================*/

func OnConfigChange(filename string) (Config, error) {
	temp := new(Config)
	config1, err := temp.ReadConfig(filename)
	if err != nil {
		err2 := errors.New("Could not read the config file.")
		return config1, err2
	}

	flag2 := false
	for {
		temp2 := new(Config)
		config2, err := temp2.ReadConfig(filename)
		if err != nil {
			err2 := errors.New("Could not read the config file.")
			return config2, err2
		}

		if len(config1) != len(config2) {
			return config2, nil
		}

		for _, i := range config2 {

			for j, k := range i {

				for l, m := range k {

					flag2 = false
					for _, n := range config1 {
						map1 := n[j]
						map2 := map1[l]
						if map2 == m {
							flag2 = true
						}
					}
					if flag2 == false {
						return config2, nil
					}
				}
			}
		}
	}
}

func (c *Config) ReadConfig(filename string) (Config, error) {

	file, err := os.Open(filename)
	if err != nil {
		err2 := errors.New("Could not open the config file.")
		return nil, err2
	}
	defer file.Close()

	var element map[string]map[string]string
	var FirstLayer string
	buf := bufio.NewReader(file)

	for {

		l, err := buf.ReadString('\n')
		line := strings.TrimSpace(l)
		if err != nil {
			if err != io.EOF {
				err2 := errors.New("Could not read the config element.")
				return nil, err2
			}
			if len(line) == 0 {
				break
			}
		}

		switch {

		case len(line) == 0:
		case string(line[0]) == sys:

		case line[0] == '[' && line[len(line)-1] == ']':
			FirstLayer = strings.TrimSpace(line[1 : len(line)-1])
			element = make(map[string]map[string]string)
			element[FirstLayer] = make(map[string]string)

		default:
			index := strings.IndexAny(line, "=")
			value := strings.TrimSpace(line[index+1 : len(line)])
			if FirstLayer == "" {
				FirstLayer = "FirstLayer"
			}
			element = make(map[string]map[string]string)
			element[FirstLayer] = make(map[string]string)
			valmap := strings.TrimSpace(line[0:index])
			element[FirstLayer][valmap] = value
			*c = append(*c, element)
		}
	}

	return *c, nil
}
